﻿using IGeekFan.AspNetCore.Knife4jUI;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models;
using Pay.DTO;
using Pay.Services;
using Pay.Services.Imp;
using Polly.Extensions.Http;
using Polly;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.DependencyInjection;

namespace Pay.Core
{
    /// <summary>
    /// startup
    /// </summary>
    public static class Startup
    {
        /// <summary>
        /// 注入服务
        /// </summary>
        public static void AddServiceCore(this IServiceCollection services)
        {
            services.AddMemoryCache();
            services.AddEndpointsApiExplorer();
            services.AddSwaggerGen(option =>
            {
                option.CustomOperationIds(apiDesc =>
                {
                    var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
                    return controllerAction.ControllerName + "-" + controllerAction.ActionName;
                });
                option.SwaggerDoc("v1", new OpenApiInfo { Title = "通用支付网关", Version = "v1", Description = "简单易用的支付网关" });
                option.IgnoreObsoleteActions();
                //option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey });
                //option.AddSecurityRequirement(new OpenApiSecurityRequirement());
                option.SchemaFilter<EnumSchemeFilter>();
                option.DocumentFilter<EnumDocumentFilter>();
                var xmlpath = Path.Combine(AppContext.BaseDirectory, "Pay.xml");
                if (File.Exists(xmlpath))
                    option.IncludeXmlComments(xmlpath, true);
            });
            services.AddHttpClient("push.client").AddPolicyHandler(GetRetryPolicy());
            services.AddAuthentication(AuthHandler.SchemeName)
                .AddScheme<AuthenticationSchemeOptions, AuthHandler>(AuthHandler.SchemeName, null);
            services.AddMvc().AddJsonOptions(jsonOption =>
            {
                jsonOption.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
                jsonOption.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
                jsonOption.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString;
                jsonOption.JsonSerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
                jsonOption.JsonSerializerOptions.Converters.Add(new JsonEnumConverter());
            }).ConfigureApiBehaviorOptions(option =>
            {
                option.InvalidModelStateResponseFactory = context =>
                {
                    var result = new BaseResultDto { Code = 405, Msg = string.Join('|', context.ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage))) };
                    return new ObjectResult(result);
                };
            });
            services.AddRouting(option =>
            {
                option.LowercaseUrls = true;
            });
            services.AddCors(corOption =>
            {
                corOption.AddDefaultPolicy(policyBuidler =>
                {
                    policyBuidler.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
                });
            });
            services.AddAlipay();
            services.AddWeChatPay();
            services.AddScoped<PayConfigDto>();
            services.AddHostedService<MyHostedService>();
            services.AddTransient<IPayService, PayService>();
        }

        /// <summary>
        /// 注册中间件
        /// </summary>
        public static void UseMiddlewareCore(this IApplicationBuilder app)
        {
            app.UseSwagger();
            app.UseKnife4UI(knifeUI =>
            {
                knifeUI.EnableFilter();
                knifeUI.DisplayOperationId();
            });
            app.UseStaticFiles();
            app.UseMiddleware<ExceptionMiddleware>();
            app.UseMiddleware<HealthMiddleware>();
            app.UseCors();
            app.UseHttpsRedirection();
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
            });
        }

        #region private methods
        /// <summary>
        /// 重试策略
        /// </summary>
        private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
        {
            return HttpPolicyExtensions
                .HandleTransientHttpError()
                .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound || msg.StatusCode == System.Net.HttpStatusCode.RequestTimeout)
                .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
        }
        #endregion
    }
}